package com.yinhai.ta404.component.security.base.handler;

import com.yinhai.ta404.component.org.sysmg.resource.service.write.impl.ResourceWriteServiceImpl;
import com.yinhai.ta404.component.security.base.access.IMenuStore;
import com.yinhai.ta404.component.security.base.autoconfigure.WebSecurityConfig;
import com.yinhai.ta404.component.security.base.service.TaUserAutoUnlockService;
import com.yinhai.ta404.component.security.base.user.TaUserDetails;
import com.yinhai.ta404.core.IConstants;
import com.yinhai.ta404.core.event.EventPublish;
import com.yinhai.ta404.core.restservice.resultbean.ResultBean;
import com.yinhai.ta404.core.security.service.ITaCustomResourceReadService;
import com.yinhai.ta404.core.security.service.ITaResourceReadService;
import com.yinhai.ta404.core.security.service.ITaUserReadService;
import com.yinhai.ta404.core.security.vo.*;
import com.yinhai.ta404.core.utils.JsonFactory;
import com.yinhai.ta404.core.utils.ServiceLocator;
import com.yinhai.ta404.core.utils.ValidateUtil;
import com.yinhai.ta404.core.utils.WebUtil;
import com.yinhai.ta404.module.hunan.userarea.service.read.UserAreaReadService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.net.InetAddress;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

import static com.yinhai.ta404.core.security.ISecurityConstants.*;



public abstract class TaLoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

    private static final Logger logger = LoggerFactory.getLogger(TaLoginSuccessHandler.class);

    @Resource
    private EventPublish eventPublish;

    @Resource
    private UserAreaReadService userAreaReadService;
    @Resource
    private ITaUserReadService userReadService;

    @Resource
    private ITaResourceReadService taResourceReadService;

    @Resource
    private ITaCustomResourceReadService customResourceReadService;

    @Autowired
    private TaUserAutoUnlockService taUserAutoUnlockService;

    @Autowired
    private WebSecurityConfig securityConfig;

    @Value("${ta404.component.security.openSso}")
    private String openSso;

    protected TaLoginSuccessHandler() {
    }

    
    protected abstract void doLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
                                            Authentication authentication);

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws IOException {
        if (logger.isInfoEnabled()) {
            logger.info("-----登录成功，INFO:{}-----", request.getRemoteAddr());
        }
        doLogoutSuccess(request, response, authentication);


        TaUserDetails userDetails = (TaUserDetails) authentication.getPrincipal();
        UserAccountVo userAccountVo = userDetails.getUser();

        HttpSession session = request.getSession(true);

        List<BaseRoleVo> roles = userDetails.getUser().getRoles();
        String userId = userAccountVo.getUserId();


        if(ValidateUtil.isEmpty(this.openSso) || !Boolean.valueOf(this.openSso)){
            taUserAutoUnlockService.resetLockUser(userId);
        }


        List<BaseResourceVo> resourceVos = new ArrayList<>(0);

        if (!userReadService.isDeveloper(userId)) {
            resourceVos = taResourceReadService.queryResourceEffectiveWithUserId(userId);
        }


        List<BaseOrgVo> orgAuthInfo = new ArrayList<>(0);
        List<String> dictAuthInfo = new ArrayList<>(0);
        Map<String, List<BaseCustomResourceVo>> customResourceVoMap = new HashMap<>(4);
        if (securityConfig.getLoadCustomAuth()) {

            if (!userReadService.isDeveloper(userId)) {


                customResourceVoMap = customResourceReadService.queryCustomAuthByUserId(userId);


                orgAuthInfo = new ArrayList<>(customResourceReadService.queryOrgAuthInfo(customResourceVoMap));
            } else {
                customResourceVoMap = customResourceReadService.queryCustomAuthByDev();
                orgAuthInfo = new ArrayList<>(customResourceReadService.queryOrgAuthInfoByDev());
            }

            dictAuthInfo = new ArrayList<>(customResourceReadService.queryDictAuthInfo(customResourceVoMap));

        }

        List<BaseResourceVo> queryResourceNoLogin = taResourceReadService.queryResourceNoLogin();
        List<BaseResourceVo> queryResourceLogin = taResourceReadService.queryResourceLogin();
        Map<String, Set<RestUrlVo>> map = new HashMap<>(64);
        Map<String, Set<RestUrlVo>> btnAuthMap = new HashMap<>(32);
        Set<String> btnSet = new HashSet<>(16);
        Set<String> resourceSet = new HashSet<>(32);
        if (ValidateUtil.isNotEmpty(resourceVos)) {
            resourceVos.forEach(vo -> {
                List<RestUrlVo> urlVoList = vo.getRestUrlList();
                if (ValidateUtil.isNotEmpty(urlVoList)) {
                    if (!ResourceWriteServiceImpl.BUTTON_TYPE.equals(vo.getField01())) {
                        map.put(vo.getResourceId(), new HashSet<>(urlVoList));
                        resourceSet.add(vo.getResourceId());
                    } else {
                        Set<RestUrlVo> set = btnAuthMap.computeIfAbsent(vo.getpResourceId(), k -> new HashSet<>());
                        set.addAll(urlVoList);
                        btnAuthMap.put(vo.getpResourceId(), set);
                        btnSet.add(vo.getResourceId());
                    }
                }
            });
        }

        Map<String, Set<RestUrlVo>> btnNoAuthMap = taResourceReadService.queryBtnInfoWithRestUrl(new ArrayList<>(resourceSet), new ArrayList<>(btnSet));

        Map<String, Set<String>> btnNoAuthUrlMap = new HashMap<>(32);
        btnNoAuthMap.forEach((k,v) -> {
            Set<String> set = v.stream().map(RestUrlVo::getRestUrl).collect(Collectors.toSet());
            btnNoAuthUrlMap.put(k, set);
        });


        userAccountVo.setUserAreas(this.userAreaReadService.queryAreaByUserId(userId));


        session.setAttribute(USER_INFO, userDetails.getUser());
        session.setAttribute(CURRENT_MENU, resourceVos);
        session.setAttribute(CURRENT_ROLE, roles);
        session.setAttribute(IMenuStore.BTN_AUTH_KEY, btnAuthMap);
        session.setAttribute(IMenuStore.BTN_NO_AUTH_KEY, btnNoAuthUrlMap);
        session.setAttribute(IMenuStore.RESOURCE_AUTH_KEY, map);
        session.setAttribute(PERMIT_MENU, queryResourceNoLogin);
        session.setAttribute(LOGIN_PERMIT_MENU, queryResourceLogin);

        session.setAttribute(CURRENT_CUSTOM_ORG, orgAuthInfo);
        session.setAttribute(CURRENT_CUSTOM_DICT, dictAuthInfo);
        session.setAttribute(CURRENT_CUSTOM_MAP, customResourceVoMap);


//        taUserWriteService.updateUserPasswordNumByUserId(userAccountVo.getUserId(), 0, IConstants.NO);
        session.removeAttribute(IConstants.PW_VALIDATION_ERROR_NUMBER + userAccountVo.getLoginId());


        Map<String, Object> eventDto = new HashMap<>(16);
        eventDto.put(EVENT_PARAM_SESSION, session);
        eventDto.put(EVENT_PARAM_SESSIONID, session.getId());
        eventDto.put(EVENT_PARAM_USERID, userDetails.getUser().getUserId());
        eventDto.put(EVENT_PARAM_CLIENTIP, WebUtil.getClientIp(request));
        eventDto.put(EVENT_PARAM_SERVERIP, InetAddress.getLocalHost().getHostAddress());
        eventDto.put(EVENT_PARAM_SESSIONTIME, new Timestamp(request.getSession().getLastAccessedTime()));
        eventDto.put(EVENT_PARAM_CLIENTSYSTEM, request.getParameter(REQUEST_PARAM_CLIENTSYSTEM));
        eventDto.put(EVENT_PARAM_CLIENTBROWSER, request.getParameter(REQUEST_PARAM_CLIENTBROWSER));
        eventDto.put(EVENT_PARAM_CLIENTSCREENSIZE, request.getParameter(REQUESTPARAM_CLIENTSCREENSIZE));
        eventPublish.publish(eventDto, IConstants.LOGIN_EVENT_ID);


        response.setContentType("application/json;charset=UTF-8");
        ResultBean resultBean = ServiceLocator.getAppContext().getBean(ResultBean.class);
        resultBean.setCode(200);
        resultBean.setSuccess(true);
        response.getWriter().write(JsonFactory.bean2json(resultBean));
    }
}
